#include "stdafx.h"

#include "v_socket.h"
#include <Winsock2.h>
#include "v_address.h"


#define DEFAULT_SOCKET_TIMEOUT (10*1000)

VSocket::VSocket() : m_socket(0)
{
}

int VSocket::create()
{
	m_socket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == m_socket)
	{
		m_socket = 0;
		throw "invalid socket when create socket"; 
	}

	return 1;
}

VSocket::~VSocket()
{
	close();
}

void VSocket::connect(const char* address, unsigned short port) const
{
	sockaddr_in bsockaddr;
	VAddress addr(address, port);
	addr.getAddr(&bsockaddr);
	int len = sizeof(sockaddr_in);

	DWORD timeOut= 10000;

	if(SOCKET_ERROR == ::setsockopt(m_socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeOut,sizeof(timeOut)))
	{
		throw "setsockopt error";
	}

	if(SOCKET_ERROR == ::setsockopt(m_socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeOut,sizeof(timeOut)))
	{
		throw "setsockopt error";
	}

	if (SOCKET_ERROR == ::connect(m_socket, (sockaddr*)&bsockaddr, len)) 
	{
		throw "connect error";
	}

	char chOpt = 1;
	if(SOCKET_ERROR == ::setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&chOpt, sizeof(chOpt)))
	{
		throw "setsockopt error";
	}
}

void VSocket::bind(const char* address, unsigned short port) const
{
	sockaddr_in bsockaddr;
	VAddress addr(address, port);
	addr.getAddr(&bsockaddr);
	int len = sizeof(sockaddr_in);
	if (SOCKET_ERROR == ::bind(m_socket, (sockaddr*)&bsockaddr, len))
	{
		throw "bind error";
	}
}

void VSocket::bind(unsigned short port) const
{
	sockaddr_in bsockaddr = {0};
	bsockaddr.sin_family = AF_INET;
	bsockaddr.sin_addr.s_addr = INADDR_ANY;
	bsockaddr.sin_port = htons(port);
	int len = sizeof(sockaddr_in);
	if (SOCKET_ERROR == ::bind(m_socket, (sockaddr*)&bsockaddr, len))
	{
		throw "bind error";
	}
}

void VSocket::listen(int backlog) const
{
	if (SOCKET_ERROR ==::listen(m_socket, backlog))
	{
		throw "listen error";
	}
}

void VSocket::accept(VSocket* pSocket, VAddress* pAddress) const
{
	if (!pSocket)
	{
		return;
	}
	
	int len = sizeof(sockaddr_in);
	sockaddr_in addr;
	SOCKET s = ::accept(m_socket, (sockaddr*)&addr, &len);
	if (INVALID_SOCKET  == s)
	{
		throw "accept error";
	}
	if (pAddress)
	{
		*pAddress = VAddress(&addr);
	}
	pSocket->m_socket = s;
}

void VSocket::close()
{
	if (m_socket != 0)
	{
		::closesocket(m_socket);
		m_socket = 0;
	}
}

int VSocket::send(const char* buf, int len) const
{
	return ::send(m_socket, buf, len, 0);
}

#include <stdio.h>

#define LOG_TO_FILE

static void log_to_file(const char* str)
{
#ifdef LOG_TO_FILE
	if (!str)
	{
		return;
	}

	SYSTEMTIME st = {0};
	GetLocalTime(&st);

	FILE* fp = fopen("d:\\aftp_client_log.txt", "a");
	if (!fp)
	{
		return;
	}
	fprintf(fp, "[%d-%d-%d %d:%d:%d] %s\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, str);
	fclose(fp);
#endif
}

static void handle_socket_error(int code)
{
	char buf[1024];
	sprintf(buf, "debug: read_result, socket error code: %d", code);
	log_to_file(buf);
	switch (code)
	{
	case WSANOTINITIALISED:
		log_to_file("WSANOTINITIALISED");
		break;
	case WSAENETDOWN:
		log_to_file("WSAENETDOWN");
		break;
	case WSAEFAULT:
		log_to_file("WSAEFAULT");
		break;
	case WSAENOTCONN:
		log_to_file("WSAENOTCONN");
		break;
	case WSAEINTR:
		log_to_file("WSAEINTR");
		break;
	case WSAEINPROGRESS:
		log_to_file("WSAEINPROGRESS");
		break;
	case WSAENETRESET:
		log_to_file("WSAENETRESET");
		break;
	case WSAENOTSOCK:
		log_to_file("WSAENOTSOCK");
		break;
	case WSAEOPNOTSUPP:
		log_to_file("WSAEOPNOTSUPP");
		break;
	case WSAESHUTDOWN:
		log_to_file("WSAESHUTDOWN");
		break;
	case WSAEMSGSIZE:
		log_to_file("WSAEMSGSIZE");
		break;
	case WSAEINVAL:
		log_to_file("WSAEINVAL");
		break;
	case WSAECONNABORTED:
		log_to_file("WSAECONNABORTED");
		break;
	case WSAETIMEDOUT:
		log_to_file("WSAETIMEDOUT");
		break;
	case WSAECONNRESET:
		log_to_file("WSAECONNRESET");
		break;
	default:
		log_to_file("default socket error");
		break;
	}
}

void VSocket::sendAll(const char* buf, int len) const
{
	char tmpbuf[256];

	if (len == 0) {
		len = strlen(buf);
	}	

	sprintf(tmpbuf, "socket: %d", m_socket);
	log_to_file(tmpbuf);
	int startPos = 0;
	while ( len - startPos > 0)
	{
		sprintf(tmpbuf, "startPos: %d, len: %d", startPos, len);
		log_to_file(tmpbuf);
		int sendLen = send(buf + startPos, len - startPos);
		if (sendLen < 0) 
		{
			int error_code = ::WSAGetLastError();
			handle_socket_error(error_code);
			throw "send error";
		}
		sprintf(tmpbuf, "sendLen: %d", sendLen);
		log_to_file(tmpbuf);
		startPos += sendLen;
	}
}

int VSocket::recv(char* buf, int len) const
{
	return ::recv(m_socket, buf, len, 0);
}

int VSocket::recv() const
{
	char c;
	if (recv(&c ,1) < 0) 
	{
		int error_code = ::WSAGetLastError();
		handle_socket_error(error_code);
		return -1;
	}
	return c;
}

void VSocket::recvAll(char* buf, int len) const
{
	int startPos = 0;
	while ( len - startPos > 0)
	{
		startPos += recv(buf + startPos, len - startPos);
	}
}

